#ifndef xpack_concurrency_lock_dual_way_barrier
#define xpack_concurrency_lock_dual_way_barrier
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::concurrency_lock_dual_way_barrier::inc
#include"concurrency/lock/atom_store.hpp"
#include"concurrency/lock/atom_fetch_add.hpp"
#include"concurrency/lock/atom_fetch_sub.hpp"
#include"concurrency/lock/cache_load.hpp"
#include"concurrency/lock/cache_store.hpp"
#include"concurrency/lock_state_t.hpp"
#include"concurrency/thread_self.hpp"
#include"macro/xexport.hpp"
#include"macro/xmodify.hpp"
#include"macro/xstruct.hpp"
#pragma pop_macro("xuser")

namespace mixc::concurrency_lock_dual_way_barrier{
    // 目前只支持两组
    // 9000041 后边的素数是 9000059
    // 当有三个或三个以上的组时，会出现多个小素数 + 多个较大素数可以整除中间大小素数的情况
    // 在枚举过程中发现数值较小的 x,y,z 就可以满足条件，所以三个或三个以上的组是不适合的
    // 这个可以以后枚举更多情况，筛选出合适的值
    // 
    // for(int x = 0; x < 1024; x++){
    //     for(int y = 0; y < 1024; y++){
    //         for(int z = 0; z < 1024; z++){
    //             if (9000011 * x + 9000059 * y == 9000041 * z){
    //                 xhint(x, y, z);
    //             }
    //         }
    //     }
    // }
}

namespace mixc::concurrency_lock_dual_way_barrier::origin{
    using inc::lock_state_t;

    constexpr uxx dual_way_channel0 = 9000011;
    constexpr uxx dual_way_channel1 = 9000041;

    xstruct(
        xname(dual_way_barrier),
        xprof(m_primer_sum, uxx)
    )
    public:
        dual_way_barrier() : 
            m_primer_sum{} {

            // 避免多核 cpu cache 问题
            inc::atom_store(xmodify(m_primer_sum), 0);
        }

        /**
         * @brief 
         * 尝试获取锁，
         * @param primer_value dual_way_channel0/dual_way_channel1 中的任意一者
         * @return lock_state_t 
         */
        lock_state_t try_lock(uxx primer_value) const {
            if (inc::atom_fetch_add(& m_primer_sum, primer_value) % primer_value == 0){
                inc::cache_load();
                return lock_state_t::accept;
            }
            else{
                inc::atom_fetch_sub(& m_primer_sum, primer_value);
                return lock_state_t::blocked;
            }
        }

        /**
         * @brief 
         * 尝试获取锁
         * 即使获取到锁，也不会刷新当前 cpu cache，该接口有更好的性能，但要求开发者保证内存可见性的正确
         * @param primer_value dual_way_channel0/dual_way_channel1 中的任意一者
         * @return lock_state_t 
         */
        lock_state_t try_lock_non_load(uxx primer_value) const {
            if (inc::atom_fetch_add(& m_primer_sum, primer_value) % primer_value == 0){
                return lock_state_t::accept;
            }
            else{
                inc::atom_fetch_sub(& m_primer_sum, primer_value);
                return lock_state_t::blocked;
            }
        }

        /**
         * @brief 
         * 尝试获取锁，如果尝试失败就会停留在该函数中
         * @param primer_value dual_way_channel0/dual_way_channel1 中的任意一者
         */
        void lock(uxx primer_value) const {
            while(true){
                if (try_lock(primer_value) == lock_state_t::accept){
                    return;
                }
                inc::thread_self::yield();
            }
        }

        /**
         * @brief 
         * 尝试获取锁，如果尝试失败就会停留在该函数中
         * 即使获取到锁，也不会刷新当前 cpu cache，该接口有更好的性能，但要求开发者保证内存可见性的正确
         * @param primer_value dual_way_channel0/dual_way_channel1 中的任意一者
         */
        void lock_non_load(uxx primer_value) const {
            while(true){
                if (try_lock_non_load(primer_value) == lock_state_t::accept){
                    return;
                }
                inc::thread_self::yield();
            }
        }

        /**
         * @brief 
         * 带锁的闭包，只有获取到锁后才会执行 call
         * @param primer_value dual_way_channel0/dual_way_channel1 中的任意一者
         * @tparam callback_t 回调函数类型
         */
        template<class callback_t>
        void lock(uxx primer_value, callback_t const & call) const {
            lock(primer_value);
            call();
            unlock(primer_value);
        }

        /**
         * @brief 
         * 带锁的闭包，只有获取到锁后才会执行 call
         * 即使获取到锁，也不会刷新当前 cpu cache，该接口有更好的性能，但要求开发者保证内存可见性的正确
         * @param primer_value dual_way_channel0/dual_way_channel1 中的任意一者
         * @tparam callback_t 回调函数类型
         */
        template<class callback_t>
        void lock_non_load_store(uxx primer_value, callback_t const & call) const {
            lock_non_load(primer_value);
            call();
            unlock_non_store(primer_value);
        }

        /**
         * @brief 解锁
         * @param primer_value dual_way_channel0/dual_way_channel1 中的任意一者
         */
        void unlock(uxx primer_value) const {
            inc::cache_store();
            inc::atom_fetch_sub(& m_primer_sum, primer_value);
        }

        /**
         * @brief 解锁
         * 不会主动将当前 cpu 的修改从 cache 保存到内存中，
         * 该接口有更好的性能，但要求开发者保证内存可见性的正确
         * @param primer_value dual_way_channel0/dual_way_channel1 中的任意一者
         */
        void unlock_non_store(uxx primer_value) const {
            inc::atom_fetch_sub(& m_primer_sum, primer_value);
        }
    $
}

#endif

xexport_space(mixc::concurrency_lock_dual_way_barrier::origin)